🎖️GitЯра🎖️
Commit 878905aea3776316a2dbed2e441a2c4a16a8eba4
Parents : dea364d
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-04-15T10:48:26-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-04-15T15:48:26Z
perf(messaging): batch node + reply lookups in message loading (#5149)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Changes
2 files changed, 49 insertions(+), 18 deletions(-)
Diff
diff --git a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt
index 04e09eaf73..a5664b1a04 100644
--- a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt
+++ b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt
@@ -28,6 +28,7 @@ import kotlinx.coroutines.withContext
import okio.ByteString.Companion.toByteString
import org.koin.core.annotation.Single
import org.meshtastic.core.database.DatabaseProvider
+import org.meshtastic.core.database.entity.PacketEntity
import org.meshtastic.core.database.entity.toReaction
import org.meshtastic.core.di.CoroutineDispatchers
import org.meshtastic.core.model.ContactSettings
@@ -154,13 +155,14 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
else -> dao.getMessagesFrom(contact)
}
flow.mapLatest { packets ->
+ val cachedGetNode = memoize(getNode)
+ val replyIds = packets.mapNotNull { it.packet.data.replyId?.takeIf { id -> id != 0 } }.distinct()
+ val replyMap = batchGetPacketsByIds(replyIds)
packets.map { packet ->
- val message = packet.toMessage(getNode)
- message.replyId
- .takeIf { it != null && it != 0 }
- ?.let { getPacketByPacketIdInternal(it) }
- ?.let { originalPacket -> originalPacket.toMessage(getNode) }
- ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message
+ val message = packet.toMessage(cachedGetNode)
+ val replyId = message.replyId?.takeIf { it != 0 }
+ val originalMessage = replyId?.let { replyMap[it] }?.toMessage(cachedGetNode)
+ if (originalMessage != null) message.copy(originalMessage = originalMessage) else message
}
}
}
@@ -177,13 +179,16 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
)
.flow
.map { pagingData ->
+ val cachedGetNode = memoize(getNode)
+ val replyCache = mutableMapOf<Int, PacketEntity?>()
pagingData.map { packet ->
- val message = packet.toMessage(getNode)
- message.replyId
- .takeIf { it != null && it != 0 }
- ?.let { getPacketByPacketIdInternal(it) }
- ?.let { originalPacket -> originalPacket.toMessage(getNode) }
- ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message
+ val message = packet.toMessage(cachedGetNode)
+ val replyId = message.replyId?.takeIf { it != 0 }
+ val originalMessage =
+ replyId
+ ?.let { id -> replyCache.getOrPut(id) { getPacketByPacketIdInternal(id) } }
+ ?.toMessage(cachedGetNode)
+ if (originalMessage != null) message.copy(originalMessage = originalMessage) else message
}
}
@@ -204,13 +209,16 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
)
.flow
.map { pagingData ->
+ val cachedGetNode = memoize(getNode)
+ val replyCache = mutableMapOf<Int, PacketEntity?>()
pagingData.map { packet ->
- val message = packet.toMessage(getNode)
- message.replyId
- .takeIf { it != null && it != 0 }
- ?.let { getPacketByPacketIdInternal(it) }
- ?.let { originalPacket -> originalPacket.toMessage(getNode) }
- ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message
+ val message = packet.toMessage(cachedGetNode)
+ val replyId = message.replyId?.takeIf { it != 0 }
+ val originalMessage =
+ replyId
+ ?.let { id -> replyCache.getOrPut(id) { getPacketByPacketIdInternal(id) } }
+ ?.toMessage(cachedGetNode)
+ if (originalMessage != null) message.copy(originalMessage = originalMessage) else message
}
}
@@ -230,6 +238,19 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
private suspend fun getPacketByPacketIdInternal(packetId: Int) =
withContext(dispatchers.io) { dbManager.currentDb.value.packetDao().getPacketByPacketId(packetId) }
+ private suspend fun batchGetPacketsByIds(ids: List<Int>): Map<Int, PacketEntity> = if (ids.isEmpty()) {
+ emptyMap()
+ } else {
+ withContext(dispatchers.io) {
+ dbManager.currentDb.value.packetDao().getPacketsByPacketIds(ids).associateBy { it.packet.packetId }
+ }
+ }
+
+ private fun memoize(getNode: suspend (String?) -> Node): suspend (String?) -> Node {
+ val cache = mutableMapOf<String?, Node>()
+ return { id -> cache.getOrPut(id) { getNode(id) } }
+ }
+
override suspend fun insert(
packet: DataPacket,
myNodeNum: Int,
diff --git a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt
index 71017799ce..c2ef9c5164 100644
--- a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt
+++ b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt
@@ -309,6 +309,16 @@ interface PacketDao {
)
suspend fun getPacketByPacketId(packetId: Int): PacketEntity?
+ @Transaction
+ @Query(
+ """
+ SELECT * FROM packet
+ WHERE packet_id IN (:packetIds)
+ AND (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node))
+ """,
+ )
+ suspend fun getPacketsByPacketIds(packetIds: List<Int>): List<PacketEntity>
+
@Query(
"""
SELECT * FROM packet
Served by rngit 1.5.0 - Generated in 0.05s